@file:Suppress("unused")

package com.hjh.tool.util

import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.*
import com.elvishew.xlog.XLog
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.runBlocking
import java.io.IOException

object DataStoreUtil {

    lateinit var dataStore: DataStore<Preferences>

    fun init(dataStore: DataStore<Preferences>) {
        this.dataStore = dataStore
    }

    // region 获取数据（异步）
    inline fun <reified T> getFlow(key: String, default: T): Flow<T> {
        val prefKey = preferenceKey<T>(key)
        return dataStore.data
            .catch { exception ->
                if (exception is IOException) {
                    XLog.tag("DataStoreUtil").e("IOException: ${exception.message}")
                    emit(emptyPreferences())
                } else {
                    throw exception
                }
            }
            .map { it[prefKey] ?: default }
    }
    // endregion

    // region 获取数据（同步，阻塞）
    inline fun <reified T> getBlocking(key: String, default: T): T = runBlocking {
        val prefKey = preferenceKey<T>(key)
        dataStore.data.first()[prefKey] ?: default
    }
    // endregion

    // region 保存数据（异步）
    suspend inline fun <reified T> put(key: String, value: T) {
        val prefKey = preferenceKey<T>(key)
        dataStore.edit { it[prefKey] = value }
    }
    // endregion

    // region 保存数据（同步，阻塞）
    inline fun <reified T> putBlocking(key: String, value: T) = runBlocking {
        put(key, value)
    }
    // endregion

    // 删除单个键
    suspend fun remove(key: String) {
        dataStore.edit { it.remove(stringPreferencesKey(key)) }
    }

    fun removeBlocking(key: String) = runBlocking { remove(key) }

    // 清空所有键
    suspend fun clear() {
        dataStore.edit { it.clear() }
    }

    fun clearBlocking() = runBlocking { clear() }

    // region 工具方法：动态生成对应类型的 Preferences.Key
    @Suppress("UNCHECKED_CAST")
    inline fun <reified T> preferenceKey(key: String): Preferences.Key<T> = when (T::class) {
        String::class -> stringPreferencesKey(key)
        Int::class -> intPreferencesKey(key)
        Boolean::class -> booleanPreferencesKey(key)
        Float::class -> floatPreferencesKey(key)
        Long::class -> longPreferencesKey(key)
        else -> throw IllegalArgumentException("Unsupported type: ${T::class.simpleName}")
    } as Preferences.Key<T>
    // endregion
}
